#include "textflag.h"
// ----函数语法---
// 函数标识符通过TEXT汇编指令定义，表示该行开始的指令定义在TEXT内存段
// 函数的定义的语法

// TEXT symbol(SB), [flags,] $framesize[-argsize] // TEXT指令、函数名、可选的flags标志、函数帧大小和可选的函数参数大小

// 两种定义方式
// 第一种是最完整的写法：函数名部分包含了当前包的路径，同时指明了函数的参数大小为32个字节（对应参数和返回值的4个int类型）。
// 第二种写法则比较简洁，省略了当前包的路径和参数的大小。如果有NOSPLIT标注，会禁止汇编器为汇编函数插入栈分裂的代码
TEXT ·Swap(SB),NOSPLIT,$0-32 // func Swap(a, b int) (int, int)

TEXT ·Swap(SB),NOSPLIT,$0 // func Swap(a, b int) (int, int)


// ---- 函数参数和返回值---
// 从代码可以看出a、b、ret0和ret1的内存地址是依次递增的，FP伪寄存器是第一个变量的开始地址。
TEXT ·Swap(SB),NOSPLIT,$0-32
    MOVQ a+0(FP),AX // AX = a
    MOVQ b+8(FP),BX // BX = b
    MOVQ BX,ret0+16(FP) // ret0 = BX
    MOVQ AX,ret1+24(FP) // ret1 = AX
    RET

// ---- 参数和返回值的内存布局 ----
// 参数和返回值需要对齐对自身大小的整数倍；
// 如：a是bool类型，大小1字节，b是int16类型，大小2字节，虽然a和b相邻，但是b大小是2字节，所以a和b直接需要有1个字节空洞
// c是int64类型，大小8字节，所以b和c直接需要有4字节空洞；
// 这样做的原因：
// 内存对齐的主要目的是为了提高内存访问的效率。许多计算机处理器在访问对齐的数据时会更有效率，因为它们的内存子系统是以固定大小的块来操作的。
// 如果数据没有对齐，处理器可能需要进行额外的内存访问操作才能获取完整的数据。
TEXT ·Foo(SB),NOSPLIT,$0-32
    MOVEQ a+0(FP), AX
    MOVEQ b+2(FP), BX
    MOVEQ c_dat+8*1(FP), CX
    MOVEQ c_len+8*2(FP), DX
    MOVEQ c_cap+8*3(FP), DI
    RET

// ---- 函数中的局部变量 ----
// 然后通过汇编语言重新实现Foo函数，并通过伪SP来定位局部变量：
TEXT ·Foo2(SB),NOSPLIT,$32-0
    MOVQ a-30(SP),AX  // a； SP是一个真实SP
    MOVQ b-32(SP),BX  // b
    MOVQ c_data-24(SP),CX  // c.Data
    MOVQ c_lena-16(SP),DX  // c.c.Len
    MOVQ c_cap-8(SP),DI // c.Cap
    RET

// --- 调用其他函数 ---


// --- 宏函数 ---
# define SWAP(x,y,t) MOVQ x,t;MOVQ y,x;MOVQ t,y

TEXT ·Swap(SB),$0-32
    MOVQ a+0(FP),AX // ax = a
    MOVQ b+0(FP),BX // bx = b

    SWAP(AX,BX,CX) // ax,bx = b,a

    MOVQ AX,ret0+16(FP) // return
    MOVQ BX,ret1+24(FP)
    RET
